home *** CD-ROM | disk | FTP | other *** search
- using System;
- using System.Drawing;
- using System.IO;
-
- ///
- /// <summary>
- /// PCXClass.cs contain a moreless useful PCX-viewer class
- /// It will work with the most widely distributed 256 or 24bit color
- /// pictures and the older 16 bit ones.
- /// Known issues are the possibly problems with true CGA pictures
- /// and the packed 16 bit ones (with 4 planes).
- /// Some coding solution surely will be like a stone-age way
- /// for professionals, but probably not for starter ones in the C#-world.
-
- /// Example submitted by Endre I Simay based on Turbo Pascal viewer,
- ///
- /// </summary>
-
- public class VideoModes {
- public byte CGA4; // { video modes }
- public byte CGA2;
- public byte EGA ;
- public byte VGA ;
- public byte MCGA;
- public byte MCGA2;
- public VideoModes() {
- CGA4 = 0x04; // { video modes }
- CGA2 = 0x06;
- EGA = 0x10;
- VGA = 0x12;
- MCGA = 0x13;
- MCGA2 = 0x15;
- }
- }
- public class ByteBitWise {
- byte [] ext;
- public ByteBitWise () {
- ext =new byte [8];
- ext[0]=1;
- for (int i=1; i<8; i++) // {1, 2, 4, 8, 16, 32, 64, 128};
- {
- ext[i]=(byte)(ext[i-1]*2);
- }
- }
- public byte shr (byte basic, byte n) {
- return (byte)(basic/ext[n & (8-1)]);
- }
- public byte shl (byte basic, byte n) {
- return (byte)(basic*ext[n & (8-1)]);
- }
- }
- public struct BITMAPFILEHEADER {
- public UInt16 bfType;
- public UInt32 bfSize;
- public UInt16 bfReserved1;
- public UInt16 bfReserved2;
- public UInt32 bfOffBits;
- } // Size=14
-
- public struct BITMAPINFOHEADER {
- public UInt32 biSize;
- public Int32 biWidth;
- public Int32 biHeight;
- public UInt16 biPlanes;
- public UInt16 biBitCount;
- public UInt32 biCompression;
- public UInt32 biSizeImage;
- public Int32 biXPelsPerMeter;
- public Int32 biYPelsPerMeter;
- public UInt32 biClrUsed;
- public UInt32 biClrImportant;
- } // Size=40
-
- public class PCX_Header {
- public byte Manufacturer; // Always 10 for PCX file
- public byte Version;
- /* 2 - old PCX - no palette (NOT used anymore),
- 3 - no palette,
- 4 - Microsoft Windows - no palette (only in
- old files, New Windows version USES 3),
- 5 - WITH palette */
- public byte Encoding;
- /* 1 is PCX, it is possible that we may add
- additional encoding methods IN the future */
- public byte Bits_per_pixel;
- /* Number of bits to represent a pixel
- (per plane) - 1, 2, 4, or 8 */
- public Int16 Xmin; // Image window dimensions (inclusive)
- public Int16 Ymin; // Xmin, Ymin are usually zero (not always)
- public Int16 Xmax;
- public Int16 Ymax;
- public Int16 Hdpi; // Resolution of image (dots per inch)
- public Int16 Vdpi; // Set to scanner resolution - 300 is default
- public byte [,] ColorMap;
- /* RGB palette data (16 colors or less)
- 256 color palette is appended to END OF FILE */
- public byte Reserved;
- /* (used to contain video mode)
- now it is ignored - just set to zero */
- public byte Nplanes; // Number of planes
- public UInt16 Bytes_per_line_per_plane;
- /* Number of bytes to allocate
- for a scanline plane.
- MUST be an an EVEN number!
- DO NOT calculate from Xmax-Xmin! */
- public UInt16 PaletteInfo;
- /* 1 = black & white or color image,
- 2 = grayscale image - ignored IN PB4, PB4+
- palette must also be set to shades of gray! }*/
- public Int16 HscreenSize; // added for PC Paintbrush IV Plus ver 1.0,
- public Int16 VscreenSize; // PC Paintbrush IV ver 1.02 (and later)
- public byte [] Filler; // Set to zeros but mainly indifferent paddings to 128 byte
-
- public PCX_Header() {
- ColorMap = new byte [16,3];
- Filler = new byte [54];
- }
- }
-
- public class PCX_Reader {
- private Int16 PictureMode=0;
- private int Error=0;
- private int Index = 0;
- private byte data=0;
- private UInt16 bytes_per_line = 0;
- private VideoModes video = new VideoModes();
-
- private PCX_Header PCXheader;
- private int RealWidth, RealHeight =0;
- private System.IO.StreamReader PCXStream;
- private System.IO.BinaryReader breader;
- private BITMAPFILEHEADER bitmapfileheader;
- private BITMAPINFOHEADER bitmapinfoheader;
- private System.IO.BinaryWriter bwrite = new BinaryWriter(new MemoryStream());
- private string [] errors = new string []
- {
- "No problems.",
- "Problem with opening the sourcefile.",
- "Problem to read the PCX-header.",
- "Problem with initializing the BinaryReader.",
- "Not a valid PCX-file for this decoder.",
- "Problem with reading the palette.",
- "Any problem with reading from or writing to a stream of the image."
- };
-
- private void PCX_Reader_Init() {
- video = new VideoModes();
- PCXheader = new PCX_Header();
- }
-
- public PCX_Reader() {
- PCX_Reader_Init();
- }
-
- protected void Dispose (bool disposing) {
- if (disposing) {
- if (bwrite !=null) {
- bwrite.Close();
- }
- }
- }
-
- public string PCX_ErrorString() {
- return errors[Error];
- }
-
- public int PCX_ErrorNumber() {
- return Error;
- }
-
- public Stream FromStream (Stream source) {
- MemoryStream stream = new MemoryStream();
- PCXStream = new StreamReader(source);
- FromStreamToStream(stream);
- if (Error == 0)
- {
- return stream;
- } else
- {
- return null;
- }
- }
-
- public Stream FromFile (string FilePath) {
- MemoryStream stream = new MemoryStream();
- PCXStream = new StreamReader(FilePath);
- FromStreamToStream(stream);
- if (Error == 0)
- {
- return stream;
- } else
- {
- return null;
- }
- }
-
- private void FromFileToStream (string FilePath, Stream stream) {
- try {
- PCXStream = new StreamReader(FilePath);
- FromStreamToStream(stream);
- } catch (Exception) {
- Error = 1; //Problem with opening the sourcefile
- }
- }
-
- private void FromStreamToStream (Stream stream) {
- PCX_Reader_Init();
- try {
- breader = new BinaryReader(PCXStream.BaseStream);
- try {
- PCXheader.Manufacturer = breader.ReadByte();
- PCXheader.Version = breader.ReadByte();
- PCXheader.Encoding = breader.ReadByte();
- PCXheader.Bits_per_pixel = breader.ReadByte();
- PCXheader.Xmin = breader.ReadInt16();
- PCXheader.Ymin = breader.ReadInt16();
- PCXheader.Xmax = breader.ReadInt16();
- PCXheader.Ymax = breader.ReadInt16();
- PCXheader.Hdpi = breader.ReadInt16();
- PCXheader.Vdpi = breader.ReadInt16();
- for (int j = 0; j < 16; j++) {
- for (int i = 0; i < 3; i++) {
- PCXheader.ColorMap[j,i] = breader.ReadByte();
- }
- }
- PCXheader.Reserved = breader.ReadByte();
- PCXheader.Nplanes = breader.ReadByte();
- PCXheader.Bytes_per_line_per_plane = breader.ReadUInt16();
- PCXheader.PaletteInfo = breader.ReadUInt16();
- PCXheader.HscreenSize = breader.ReadInt16();
- PCXheader.VscreenSize = breader.ReadInt16();
- PCXheader.Filler = breader.ReadBytes(55);
- } catch (Exception) {
- Error=2; //Problem to read the PCX-header
- }
- } catch (Exception) {
- Error = 3; //Problem with initializing the BinaryReader
- }
- if (Error == 0) {
- if ((PCXheader.Manufacturer != 10) || (PCXheader.Encoding != 1)) {
- Error =4; //Not a valid PCX-file
- }
- if ((PCXheader.Nplanes == 3) && (PCXheader.Bits_per_pixel == 8)) {
- PictureMode = video.MCGA2;
- }
- if ((PCXheader.Nplanes == 4) && (PCXheader.Bits_per_pixel == 1)) {
- PictureMode =video.VGA;
- }
-
- if ((PCXheader.Nplanes == 1) &&(PCXheader.Bits_per_pixel == 4)) {
- Error=4; //Not a valid PCX-file for this class
- /* Not implemented yet */
- }
-
- if (PCXheader.Nplanes == 1) {
- if (PCXheader.Bits_per_pixel == 1) {
- PictureMode =video.VGA;
- /* b/w PCX saved on Windows (e.g. from Paint Shop Pro)
- working with VGA-decoding, while true CGA2
- images may cause problem
- */
- // Error=4; //Not a valid PCX-file for this class
- } else {
- if (PCXheader.Bits_per_pixel == 2) {
- PictureMode =video.CGA4;
- Error=4; //Not a valid PCX-file for this class
- } else {
- if (PCXheader.Bits_per_pixel == 8) {
- PictureMode = video.MCGA;
- if (PCXheader.Version != 5) {
- Error = 4; //Not a valid PCX-file
- }
- }
- }
- }
- }
- }
- if (Error==0) {
- bytes_per_line = (UInt16)(PCXheader.Bytes_per_line_per_plane * PCXheader.Nplanes);
- RealWidth=PCXheader.Xmax-PCXheader.Xmin+1;
- RealHeight=PCXheader.Ymax-PCXheader.Ymin+1;
- FillBitmapStructs();
- ReadPalettes(PCXStream.BaseStream);
- }
- if (breader!=null) {
- breader.Close();
- }
- if (PCXStream!=null) {
- PCXStream.Close();
- }
- if (Error==0) {
- ((MemoryStream) bwrite.BaseStream).WriteTo(stream);
- } else {
- stream.Close();
- }
- }
-
- private void FillBitmapStructs() {
- bitmapfileheader.bfType =(UInt16)0x4D42;
- bitmapfileheader.bfSize = (UInt32)((3*255) + 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */
- + ((RealHeight)*(RealWidth)));
- bitmapfileheader.bfReserved1 = 0;
- bitmapfileheader.bfReserved2 = 0;
- bitmapfileheader.bfOffBits = (4*256)+ 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */;
- bitmapinfoheader.biSize =(UInt32)40;
- bitmapinfoheader.biWidth =(Int32)RealWidth;
- bitmapinfoheader.biHeight =(Int32)RealHeight;
- bitmapinfoheader.biPlanes=(UInt16)1;// biPlanes = 1; Arcane and rarely used
- bitmapinfoheader.biBitCount=(UInt16)8; //biBitCount = 8; Most widely occurring for PCX format
- bitmapinfoheader.biCompression= (UInt32)0; // biCompression = BI_RGB; Not needed compressing for the laters
- bitmapinfoheader.biSizeImage=(UInt32)0; //biSizeImage = 0; Valid since we are not compressing the image
- bitmapinfoheader.biXPelsPerMeter =(Int32)143; //biXPelsPerMeter = 143; Rarely used (Windows not use) very arcane field
- bitmapinfoheader.biYPelsPerMeter=(Int32)143; //biYPelsPerMeter = 143; Ditto
- bitmapinfoheader.biClrUsed=(UInt32)0; //biClrUsed = 0; all colors are used
- bitmapinfoheader.biClrImportant=(UInt32)0; //biClrImportant = 0; all colors are important
- }
-
- private void ReadPalettes(Stream stream) {
- Error =0;
- if ((PictureMode == video.MCGA) && (PCXheader.Version == 5)) {
- Read256palette(stream);
- }
- if (PictureMode == video.MCGA2) {
- ReadMCGA2palette(stream);
- }
- if (PictureMode == video.VGA) {
- ReadVGA16palette(stream);
- }
- }
-
- private void Read256palette(Stream stream) // Read in a 256 color palette at end of PCX file
- {
- int bytes_in_line,dY;
- UInt16 count;
-
- byte[,] Palette256 = new byte[256, 3];
- stream.Seek( (stream.Length) - 769,0);
- // read indicator byte
- try {
- if (stream.ReadByte() == 12) {
- // read palette if there is one
- for (int j = 0; j < 256; j++) {
- for (int i = 0; i < 3; i++) {
- Palette256[j,i] = (byte)stream.ReadByte();
- }
- }
- stream.Seek(128,0); /// go back to start of PCX data
- Error = 0;
- } else {
- Error=5; // no palette here...
- }
- } catch (Exception)
- {
- Error=5; //Problem with reading the palette
- }
-
- if (Error==0) {
- try {
- bwrite.Write (bitmapfileheader.bfType);
- bwrite.Write (bitmapfileheader.bfSize);
- bwrite.Write (bitmapfileheader.bfReserved1);
- bwrite.Write (bitmapfileheader.bfReserved2);
- bwrite.Write (bitmapfileheader.bfOffBits);
- bwrite.Write (bitmapinfoheader.biSize);
- bwrite.Write (bitmapinfoheader.biWidth);
- bwrite.Write (bitmapinfoheader.biHeight);
- bwrite.Write (bitmapinfoheader.biPlanes);
- bwrite.Write (bitmapinfoheader.biBitCount);
- bwrite.Write (bitmapinfoheader.biCompression);
- bwrite.Write (bitmapinfoheader.biSizeImage);
- bwrite.Write (bitmapinfoheader.biXPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biYPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biClrUsed);
- bwrite.Write (bitmapinfoheader.biClrImportant);
- for (int i = 0; i< 256; i++) {// R, G, and B must be 0..63
- bwrite.Write((byte) Palette256 [i, 2]);
- bwrite.Write((byte) Palette256 [i, 1]);
- bwrite.Write((byte) Palette256 [i, 0]);
- bwrite.Write((byte)0);
- }
- Index = 0;
- bytes_in_line = RealWidth;
- dY = 4-(bytes_in_line-(bytes_in_line / 4)*4);
- if (dY==4) {
- dY=0;
- }
- bytes_in_line = bytes_in_line+dY;
- byte [,] lines = new byte [RealHeight,bytes_in_line];
- for (int i=0; i<(RealHeight); i++) {
- if (Index != 0) {
- for (int j=0; j<Index;j++) {
- lines[i,j]= data; // fills a contiguous block
- }
- }
- while (Index < bytes_per_line) // read 1 line of data (all planes)
- {
- data = (byte)stream.ReadByte();
- if ((byte)(data & (byte)(0xC0)) == (byte)(0xC0)) {
- count = (UInt16)((byte)(data & (byte)(0x3F)));
- data = (byte)stream.ReadByte();
- for (int j=0; j<count;j++) //(int i=Index; i<count;i++)
- {
- lines[i,Index+j]= data; // fills a contiguous block
- }
- Index += count;
- } else {
- lines [i,Index] = data;
- Index++;
- }
- }
- Index = Index - bytes_per_line;
- }
- for (int k = RealHeight-1; k>= 0; k--) {
- for (int i = 0; i<(bytes_in_line); i++) {
- bwrite.Write((byte)lines[k,i]);
- }
- }
- }catch (Exception){
- Error=6; // Any problem with reading from or writing to a stream of the image
- }
-
- }
- }
-
- private void ReadMCGA2palette(Stream stream) // Read in a 24b color PCX file
- {
- int bytes_in_line,dY;
- UInt16 count;
- stream.Seek(128,0); /// guaranted go to start of PCX data
- bytes_in_line=3*(RealWidth);
-
- dY=4-(bytes_in_line-(bytes_in_line / 4)*4);
- if (dY==4) {
- dY=0;
- }
- bytes_in_line=bytes_in_line+dY;
-
- if (Error==0) {
- try {
- bitmapfileheader.bfSize = (UInt32)((3*15) + 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */
- + ((RealHeight)*(RealWidth)*3));
- bitmapfileheader.bfOffBits = 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */;
- bitmapinfoheader.biBitCount=(UInt16)24;
- bwrite.Write (bitmapfileheader.bfType);
- bwrite.Write (bitmapfileheader.bfSize);
- bwrite.Write (bitmapfileheader.bfReserved1);
- bwrite.Write (bitmapfileheader.bfReserved2);
- bwrite.Write (bitmapfileheader.bfOffBits);
- bwrite.Write (bitmapinfoheader.biSize);
- bwrite.Write (bitmapinfoheader.biWidth);
- bwrite.Write (bitmapinfoheader.biHeight);
- bwrite.Write (bitmapinfoheader.biPlanes);
- bwrite.Write (bitmapinfoheader.biBitCount);
- bwrite.Write (bitmapinfoheader.biCompression);
- bwrite.Write (bitmapinfoheader.biSizeImage);
- bwrite.Write (bitmapinfoheader.biXPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biYPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biClrUsed);
- bwrite.Write (bitmapinfoheader.biClrImportant);
- int x =0;
- Index = 0;
- byte [,] lines = new byte [RealHeight,bytes_in_line];
- byte [] line = new byte [bytes_in_line];
- for (int i=0; i<(RealHeight); i++) {
- if (Index != 0) {
- for (int j=0; j<Index;j++)
- {
- line[j]= data; // fills a contiguous block
- }
- }
- while (Index < bytes_per_line) // read 1 line of data (all planes)
- {
- data = (byte)stream.ReadByte();
- if ((byte)(data & (byte)(0xC0)) == (byte)(0xC0)) {
- count = (UInt16)((byte)(data & (byte)(0x3F)));
- data = (byte)stream.ReadByte();
- for (int j=0; j<count;j++)
- {
- line[Index+j]= data; // fills a contiguous block
- }
- Index += count;
- } else {
- line [Index] = data;
- Index++;
- }
- }
- Index = Index - bytes_per_line;
- x=0;
- for (int L=0; L<PCXheader.Bytes_per_line_per_plane; L++) {
- lines[i,x+2]=line[L];
- lines[i,x+1]=line[L+PCXheader.Bytes_per_line_per_plane];
- lines[i,x]=line[L+2*PCXheader.Bytes_per_line_per_plane];
- lines[i,x+3]=0;
- x=x+3;
- }
- }
- for (int k = RealHeight-1; k>= 0; k--) {
- for (int i = 0; i<(bytes_in_line); i++) {
- bwrite.Write((byte)lines[k,i]);
- }
- }
- }catch (Exception){
- Error=6; // Any problem with reading from or writing to a stream of the image
- }
-
- }
- }
-
- private void ReadVGA16palette(Stream stream) // Read in a 16 color PCX file
- {
- ByteBitWise bitwise =new ByteBitWise();
- int bytes_in_line,dY;
- byte c;
-
- stream.Seek(128,0); /// guaranted go to start of PCX data
- if (Error==0) {
- try {
- bitmapfileheader.bfSize = (UInt32)((3*15) + 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */
- + ((RealHeight)*(RealWidth)));
- bitmapfileheader.bfOffBits = (4*16)+ 14 /*Sizeof(BitmapFileHeader)*/
- + 40 /* Sizeof(TBitmapInfoHeader) */;
- bitmapinfoheader.biBitCount=(UInt16)4; //biBitCount = 24;
- bwrite.Write (bitmapfileheader.bfType);
- bwrite.Write (bitmapfileheader.bfSize);
- bwrite.Write (bitmapfileheader.bfReserved1);
- bwrite.Write (bitmapfileheader.bfReserved2);
- bwrite.Write (bitmapfileheader.bfOffBits);
- bwrite.Write (bitmapinfoheader.biSize);
- bwrite.Write (bitmapinfoheader.biWidth);
- bwrite.Write (bitmapinfoheader.biHeight);
- bwrite.Write (bitmapinfoheader.biPlanes);
- bwrite.Write (bitmapinfoheader.biBitCount);
- bwrite.Write (bitmapinfoheader.biCompression);
- bwrite.Write (bitmapinfoheader.biSizeImage);
- bwrite.Write (bitmapinfoheader.biXPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biYPelsPerMeter);
- bwrite.Write (bitmapinfoheader.biClrUsed);
- bwrite.Write (bitmapinfoheader.biClrImportant);
- for (int L= 0;L<16;L++) {// R, G, and B must be 0..63
- bwrite.Write((byte) PCXheader.ColorMap [L, 2]);
- bwrite.Write((byte) PCXheader.ColorMap [L, 1]);
- bwrite.Write((byte) PCXheader.ColorMap [L, 0]);
- bwrite.Write((byte) 0);
- }
- int kmax = PCXheader.Ymin +PCXheader.Ymax;
- int x =0;
- UInt16 count;
- Index = 0;
- bytes_in_line=(RealWidth)/2;
- dY = 4-(bytes_in_line-(bytes_in_line / 4)*4);
- if (dY==4) {
- dY = 0;
- }
- bytes_in_line=bytes_in_line+dY;
- byte [,] lines = new byte [RealHeight,bytes_in_line*2];
- byte [] line = new byte [bytes_in_line*2];
- for (int i=0; i<(RealHeight); i++) {
- if (Index != 0) {
- for (int j=0; j<Index;j++) {
- line[j]= data; // fills a contiguous block
- }
- }
- while (Index < bytes_per_line) // read 1 line of data (all planes)
- {
- data = (byte)stream.ReadByte();
- if ((byte)(data & (byte)(0xC0)) == (byte)(0xC0)) {
- count = (UInt16)((byte)(data & (byte)(0x3F)));
- data = (byte)stream.ReadByte();
- for (int j=0; j<count;j++) {
- line[Index+j]= data; // fills a contiguous block
- }
- Index += count;
- } else {
- line [Index] = data;
- Index++;
- }
- }
- Index = Index - bytes_per_line;
-
- for (dY = 0; dY<bytes_in_line*2; dY++) {
- lines[i,dY]=0;
- }
- x=0;
- for (dY=0; dY<PCXheader.Nplanes; dY++) {
- for (int j=0; j<PCXheader.Bytes_per_line_per_plane; j++) {
- c = line[x];
- x++;
- for (int k=0; k<8; k++) {
- if (((byte)c & bitwise.shr(128,(byte)k)) > 0) {
- lines[i,(j*8)+k]= (byte)(lines[i,(j*8)+k] | bitwise.shl(1,(byte)dY));
- }
- }
- }
- }
- for (dY=0; dY<bytes_in_line*2; dY++) {
- line[dY]=lines[i,dY];
- }
- dY=(-1);
- x=(-1);
- while (x<(PCXheader.Xmax - PCXheader.Xmin)) {
- dY++;
- x++;
- lines[i,dY]=(byte)(bitwise.shl(line[x],4) ^ line[x+1] & 0x0F);
- x++;
- }
- }
-
- for ( int k = RealHeight-1; k>= 0; k--) {
- for ( int i = 0; i<(bytes_in_line); i++) {
- bwrite.Write((byte)lines[k,i]);
- }
- }
- }catch (Exception){
- Error=6; // Any problem with reading from or writing to a stream of the image
- }
- }
- }
-
- }
-
-